
/**
  ******************************************************************************
  * Copyright 2021 The Microbee Authors. All Rights Reserved.
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  * 
  * http://www.apache.org/licenses/LICENSE-2.0
  * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * 
  * @file       param.h
  * @author     baiyang
  * @date       2021-7-12
  ******************************************************************************
  */

#pragma once

#ifdef __cplusplus
extern "C"{
#endif

/*----------------------------------include-----------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <common/gp_defines.h>
/*-----------------------------------macro------------------------------------*/
#define PARAM_GROUP_COUNT          param_group_num

#define PARAM_INDEX_NONE           0xFFFF

#define PARAM_MAX_NAME_SIZE    16

#define PARAM_DECLARE(_name) param_t __param_##_name

#define PARAM_DEFINE_INT8(_name, _default) \
    {                                      \
        .name = #_name,                    \
        .type = PARAM_TYPE_INT8,           \
        .idx  = PARAM_INDEX_NONE,          \
        .val.i8 = _default,                \
        .default_val = (float)(_default),  \
        .user_param = NULL                 \
    }

#define PARAM_DEFINE_UINT8(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_UINT8,           \
        .idx  = PARAM_INDEX_NONE,           \
        .val.u8 = _default,                 \
        .default_val = (float)(_default),   \
        .user_param = NULL                  \
    }

#define PARAM_DEFINE_INT16(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_INT16,           \
        .idx  = PARAM_INDEX_NONE,           \
        .val.i16 = _default,                \
        .default_val = (float)(_default),   \
        .user_param = NULL                  \
    }

#define PARAM_DEFINE_UINT16(_name, _default) \
    {                                        \
        .name = #_name,                      \
        .type = PARAM_TYPE_UINT16,           \
        .idx  = PARAM_INDEX_NONE,            \
        .val.u16 = _default,                 \
        .default_val = (float)(_default),    \
        .user_param = NULL                   \
    }

#define PARAM_DEFINE_INT32(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_INT32,           \
        .idx  = PARAM_INDEX_NONE,           \
        .val.i32 = _default,                \
        .default_val = (float)(_default),   \
        .user_param = NULL                  \
    }

#define PARAM_DEFINE_UINT32(_name, _default) \
    {                                        \
        .name = #_name,                      \
        .type = PARAM_TYPE_UINT32,           \
        .idx  = PARAM_INDEX_NONE,            \
        .val.u32 = _default,                 \
        .default_val = (float)(_default),    \
        .user_param = NULL                   \
    }

#define PARAM_DEFINE_FLOAT(_name, _default) \
    {                                       \
        .name = #_name,                     \
        .type = PARAM_TYPE_FLOAT,           \
        .idx  = PARAM_INDEX_NONE,           \
        .val.f = _default,                  \
        .default_val = (float)(_default),   \
        .user_param = NULL                  \
    }


#define PARAM_GROUP_PTR(_name)         &(__param_group_##_name)
#define PARAM_GROUP_DECLARE(_name)    extern param_group_t __param_group_##_name
#define PARAM_GROUP_DEFINE(_name, _param_list) param_group_t __param_group_##_name = { \
    .name = #_name,                                                                         \
    .param_num = sizeof(_param_list) / sizeof(param_t),                                     \
    .content = _param_list                                                               \
}

#define PARAM_VALUE_INT8(_param)   (_param)->val.i8
#define PARAM_VALUE_UINT8(_param)  (_param)->val.u8
#define PARAM_VALUE_INT16(_param)  (_param)->val.i16
#define PARAM_VALUE_UINT16(_param) (_param)->val.u16
#define PARAM_VALUE_INT32(_param)  (_param)->val.i32
#define PARAM_VALUE_UINT32(_param) (_param)->val.u32
#define PARAM_VALUE_FLOAT(_param)  (_param)->val.f

#define PARAM_ID(_group, _name) param_get_by_full_name(#_group, #_name)

#define PARAM_GET_INT8(_group, _name)   PARAM_VALUE_INT8(PARAM_ID(_group, _name))
#define PARAM_GET_UINT8(_group, _name)  PARAM_VALUE_UINT8(PARAM_ID(_group, _name))
#define PARAM_GET_INT16(_group, _name)  PARAM_VALUE_INT16(PARAM_ID(_group, _name))
#define PARAM_GET_UINT16(_group, _name) PARAM_VALUE_UINT16(PARAM_ID(_group, _name))
#define PARAM_GET_INT32(_group, _name)  PARAM_VALUE_INT32(PARAM_ID(_group, _name))
#define PARAM_GET_UINT32(_group, _name) PARAM_VALUE_UINT32(PARAM_ID(_group, _name))
#define PARAM_GET_FLOAT(_group, _name)  PARAM_VALUE_FLOAT(PARAM_ID(_group, _name))
/*----------------------------------typedef-----------------------------------*/
enum param_type_t {
    PARAM_TYPE_INT8 = 0,
    PARAM_TYPE_UINT8,
    PARAM_TYPE_INT16,
    PARAM_TYPE_UINT16,
    PARAM_TYPE_INT32,
    PARAM_TYPE_UINT32,
    PARAM_TYPE_FLOAT,
    PARAM_TYPE_UNKNOWN = 0xFF
};

typedef enum {
    PARAM_YAML_PARSE_START = 0,
    PARAM_YAML_PARSE_GROUP_NAME,
    PARAM_YAML_PARSE_PARAM,
} PARAM_YAML_PARSE_STATE;

typedef union {
    int8_t i8;
    uint8_t u8;
    int16_t i16;
    uint16_t u16;
    int32_t i32;
    uint32_t u32;
    float f;
} param_value_t;

typedef struct {
    param_value_t val;
    const float default_val;
    void* user_param;
    const char* name;
    uint16_t idx;
    const uint8_t type;
} param_t;

typedef struct {
    const char* name;
    const uint32_t param_num;
    param_t* content;
} param_group_t;

/*----------------------------------variable----------------------------------*/
extern const uint8_t param_group_num;
extern param_group_t* param_group_list[];
/*-------------------------------------os-------------------------------------*/

/*----------------------------------function----------------------------------*/
void param_init(void);
void param_interface_init(void);

void param_save(void);
void param_save_to_file(void);
void param_save_if_needed(void);

void param_load(void);

param_t* param_get_first();
param_t* param_get_next_scalar(const param_t* param);

param_t* param_get_by_index(const uint32_t index);
param_t* param_get_by_name(const char* param_name);
param_t* param_get_by_full_name(const char* group_name, const char* param_name);

param_t* param_get_by_variable(void* variable);
param_t* param_get_by_variable2(const char* group_name, void* variable);

void* param_find_variable(const char* param_name, enum param_type_t *ptype);
void* param_find_variable2(const char* group_name, const char* param_name, enum param_type_t *ptype);

float param_cast_to_float(param_t* param);

int param_set_val_by_full_name(char* group_name, char* param_name, char* val);

// gcs_param中使用
// 在其他文件中请使用param_set_obj、param_save_obj等
int param_set_float(param_t* param, float _value);
void param_save_float(param_t* param);

uint32_t param_get_count(void);

void param_link_variable(param_t* param, void* variable);
void param_load_variable(const char* group_name, void* variable);

void param_set_obj(param_t* param, double _value);
void param_set_obj_and_notify(param_t* param, double _value);
void param_save_obj(param_t* param);
void param_save_obj_by_variable(void* variable);
void param_save_obj_by_variable2(const char* group_name, void* variable);
void param_set_and_save(param_t* param, double _value);
void param_set_and_save_ifchanged(param_t* param, double _value);

bool param_obj_configured(const char* group_name, void* variable);
/*------------------------------------test------------------------------------*/

#ifdef __cplusplus
}
#endif



